package com.tron.base;

import com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException;
import org.springframework.core.NestedRuntimeException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ValidationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@ControllerAdvice
public class BaseExceptionHandler {


    /**
     * 基础异常处理
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(BaseException.class)
    public Map<String, Object> baseErrorHandler(BaseException e) {
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", e.getCode());
        resultMap.put("errorMessage", e.getMessage());
        return resultMap;
    }


    /**
     * 参数绑定异常处理
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(BindException.class)
    public Map<String, Object> BindExceptionHandler(BindException e) {
        HashMap<String, Object> resultMap = new HashMap<>();
        List<ObjectError> allErrors = e.getAllErrors();
        getErrors(resultMap,allErrors);
        return resultMap;
    }


    /**
     * 方法对象参数校验异常
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Map<String, Object> MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        HashMap<String, Object> resultMap = new HashMap<>();
        BindingResult bindingResult = e.getBindingResult();
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        getErrors(resultMap,allErrors);
        return resultMap;
    }

    /**
     * sql执行异常，操作了数据库不存在的字段
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(MySQLSyntaxErrorException.class)
    public Map<String, Object> errorHandler(MySQLSyntaxErrorException e) {
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", 500);
        resultMap.put("message",e.getMessage());
        return resultMap;
    }

//    @ResponseBody
//    @ExceptionHandler(Exception.class)
//    public Map<String, Object> errorHandler(Exception e) {
//         NestedRuntimeException//异常抽象
//    }

    /**
     * 请求参数异常处理
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Map<String, Object> HttpMessageNotReadableExceptionHandler(HttpMessageNotReadableException e) {
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", 500);
        resultMap.put("message","请求参数错误");
        return resultMap;
    }

    /**
     * 内部运行异常处理
     * NestedRuntimeException
     * 	UnsupportedMediaTypeException---Content-Type类型错误
     * 	MessagingException
     * 		MessageDeliveryException--消息传递中的错误异常
     * 		MessageHandlingException--消息处理期间发生的异常
     * 		MessageConversionException--消息转换异常
     * 		MissingSessionUserException--缺少回话用户异常
     * 		DestinationResolutionException--消息解析异常
     * 		MethodArgumentResolutionException--方法参数异常
     * 			MethodArgumentNotValidException--方法参数无效异常
     * 			MethodArgumentTypeMismatchException--方法参数没有预期的类型
     * 		ScriptingException--redis脚本异常
     *         PoolException--资源池异常
     *     DataAccessException--数据访问异常
     *         DataIntegrityViolationException--唯一主键约束异常
     *         DataSourceLookupFailureException--数据源查找异常
     *         DataAccessResourceFailureException--数据库连接异常(jdbc,redis...)
     *         UncategorizedDataAccessException--不能准确分类的数据库操作异常
     *         InvalidDataAccessResourceUsageException--RDBMS关系型数据库异常
     *         	TypeMismatchDataAccessException--java类型和数据库类型不匹配
     *         	BadSqlGrammarException--错误的sql语法
     *         	InvalidDataAccessApiUsageException--java数据访问架构使用异常
     *         	PermissionDeniedDataAccessException--数据表访问异常
     *         	QueryTimeoutException--查询超时异常
     *     MaxUploadSizeExceededException--上传数据过大异常
     *         HttpMessageConversionException--http消息转换异常
     *         RemoteAccessException--远程调用异常
     *         CodecException--编码或解码异常
     *         SerializationFailedException--序列化异常
     *         RestClientException--rest请求异常
     *         AnnotationConfigurationException--注解信息异常
     *         ResponseStatusException--响应状态异常
     *         RemoteAuthenticationException--远程调用身份认证失败异常
     *         TransactionException事物异常
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(NestedRuntimeException.class)
    public Map<String, Object> NestedRuntimeExceptionHandler(NestedRuntimeException e) {
        HashMap<String, Object> resultMap = new HashMap<>();
        System.out.println("RootCause------"+e.getRootCause());
        System.out.println("Cause--------"+e.getCause());
        System.out.println("Suppressed---------"+e.getSuppressed());
        System.out.println("Class-------"+e.getClass());
        resultMap.put("code", 500);
        resultMap.put("message", e.getMessage());
        return resultMap;
    }

    /**
     * 单值参数校验异常处理
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(ValidationException.class)
    public Map<String, Object> ValidationExceptionHandler(ValidationException e) {
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", 500);
        resultMap.put("message", e.getMessage());
        return resultMap;
    }

    private void getErrors(HashMap<String, Object> map, List<ObjectError> allErrors) {
        StringBuffer stringBuffer = new StringBuffer();
        allErrors.forEach(x -> stringBuffer.append(x.getObjectName()).append(x.getDefaultMessage()).append(","));
        map.put("msg", stringBuffer.toString());
        map.put("code", 500);
    }

}
